<?php
/****************************************
 * PHPZen 架构文件
 *
 * 2011-3-7
 *
 * Bullsoft 校长 - roy@solarphp.cn
 *
 ****************************************/

//设置默认加载路径
set_include_path(get_include_path().PATH_SEPARATOR."$system/zen");
set_include_path(get_include_path().PATH_SEPARATOR."$system/app");
//包含必须的两个基础类
require_once("Zen/Class.php");
require_once("Zen/File.php");

class Zen
{
    protected static $_Zen = array(
        'start' => array(),
        'stop' => array(),
        'ini_set' => array(),
        'system' => null,
    );
    
    protected static $_status = false;

    //系统URI路径
    public static $system = null;

    //系统URL路径，以HTTP(s)开头
    public static $sysurl = null;

    //系统配置数组
    public static $config = null;

    //当前请求的名字空间：app或zen
    public static $vendor = null;

    //当前请求的模块名
    public static $module = null;

    //当前请求的动作名
    public static $action = null;

    //模型库路径
    public static $model = null;

    final private function __construct() {}

    public static function start($config)
    {
        //如果Zen已经运行，则直接返回
        if (Zen::$_status) {
            return ;
        }
        //设置全站配置文件和系统绝对路径
        Zen::$config = $config;
        Zen::$system = dirname(dirname(__FILE__));

        Zen::$sysurl = str_replace('/index.php', '', $_SERVER['SCRIPT_NAME']);
        //注册autoload handler
        spl_autoload_register(array('Zen_Class', 'autoload'));
        
        //处理ini_set设置
        $settings = Zen::$config['Zen']['ini_set'];
        foreach ($settings as $key => $val) {
            ini_set($key, $val);
        }

        //注册必须类
        $register = Zen::$config['Zen']['registry_set'];
        foreach ($register as $name => $list) {
            //填充数组，array($list, null)
            $list = array_pad((array) $list, 2, null);
            list($spec, $config) = $list;
            //注册
            Zen_Registry::set($name, $spec, $config);
        }
        
        //Start Hooks 
        $hooks = Zen::$config['Zen']['start'];
        Zen::callbacks($hooks);
        
        //太好了，Zen真的运行起来了
        Zen::$_status = true;
    }

    //渲染视图
    public static function display($module=null, $action=null)
    {
        Zen::$module = $module;
        Zen::$action = $action;
        //获得请求的模块和动作
        Zen::factory('Zen_Dispatch')->start();
        $front = Zen_Registry::get('front');
        echo $front->fetch(Zen::$module, Zen::$action);
    }

    //运行结束，执行清理
    public static function stop()
    {
        //Start Hooks 
        $hooks = Zen::$config['Zen']['stop'];
        Zen::callbacks($hooks);
        
        //删除注删的autoload handler
        spl_autoload_unregister(array('Zen_Class', 'autoload'));
        spl_autoload_unregister(array('Doctrine', 'autoload'));
        spl_autoload_unregister('smartyAutoload');
        //Zen停止运行
        Zen::$_status = false;
    }

    public static function factory($class, $config = null)
    {
        Zen_Class::autoload($class);

        $obj = new $class($config);
        // 如果是Zen_Factory的实例
        if ($obj instanceof Zen_Factory) {
            // 返回对象的工厂方法
            return $obj->factory();
        }

        // 如果是普通对象，直接返回
        return $obj;
    }

    public static function dependency($class, $spec)
    {
        // 如果$spec是对象，直接返回
        if (is_object($spec)) {
            return $spec;
        }
        // 查找注册表中对象
        if (is_string($spec)) {
            return Zen_Registry::get($spec);
        }
        
        // 如果不是上面两种情况，则现场实例化
        return Zen::factory($class, $spec);
    }

    public static function exception($spec, $code, $text = '', $info = array())
    {
        //如果$spec为NULL，则代表/app/App/Vendor下的模块抛出异常
        $m = '';
        // 判断$spec变量类型
        if (is_object($spec)) {
            // 如果是对象，则求其类名
            $class = get_class($spec);

        } else if(is_null($spec)){
            //如果$spec为NULL，就设置为模块名
            $class = ucfirst(Zen::$module);
            $m = $class.'_';
        } else {
            // 其他，则认为其为类名
            $class = (string) $spec;

        } 
        // 处理code，去掉 'ERR_' 和 'EXCEPTION_'前缀，并获取异常类后缀
        // 保留code值，因为异常类配置数组中需要code值
        $suffix = $code;
        if (strpos($suffix, 'ERR_') === 0) {
            $suffix = substr($suffix, 4);
        } elseif (strpos($suffix, 'EXCEPTION_') === 0) {
            $suffix = substr($suffix, 10);
        }
        // 把 "STUDLY_CAP_SUFFIX" 转换成 "Studly Cap Suffix"形式 ...
        $suffix = ucwords(strtolower(str_replace('_', ' ', $suffix)));
        // ... 然后 转换成 "StudlyCapSuffix"开式
        $suffix = str_replace(' ', '', $suffix);

        // 为异常类构建配置数组
        $config = array(
            'class' => $class,
            'code'  => $code,
            'text'  => $text,
            'info'  => (array) $info,
        );

        $stack = array();
        $vendor = Zen::$vendor;
        //如果访问的名字空间不是zen，则加入队列
        if ($vendor != 'zen' && !is_null($vendor)) {
            $stack[] = $vendor;
        }
        //确保zen为队列中最后一个元素
        $stack[] = 'zen';

        // 查找异常类
        foreach ($stack as $class) {
            $class = ucfirst($class)."_Exception_{$m}{$suffix}";
            try {
                if (class_exists($class)) {
                    $obj = Zen::factory($class, $config);
                    return $obj;
                }
            } catch (Exception $e) {
                //只捕捉异常
            }
        }

        //如果找不到异常类，则调用Zen异常基类
        return Zen::factory('Zen_Exception', $config);
    }
    
    //Hooks
    public static function callbacks($callbacks)
    {
        foreach ((array) $callbacks as $params) {
            // $spec是一个对象实例？类名？注册表键？
            settype($params, 'array');
            $spec = array_shift($params);
            if (! is_object($spec)) {
                // 如果不是对象，就认为它是类名　...
                $spec = (string) $spec;
                // ... 如果在注册表中存在，则返回注册表映射的值
                if (Zen_Registry::exists($spec)) {
                    $spec = Zen_Registry::get($spec);
                }
            }
            //得到要执行的方法
            $func = array_shift($params);
            //执行调用
            call_user_func_array(array($spec, $func), $params);
        }
    }

    //PHP Zen系统版本
    public static function version()
    {
        return '0.3';
    }
}